﻿using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Example1.Tests
{
    internal static class RouteTestHelper
    {
        private static HttpContextBase CreateHttpContext(string targetUrl = null, string httpMethod = "GET")
        {
            var mockRequest = new Mock<HttpRequestBase>();
            mockRequest.Setup(c => c.AppRelativeCurrentExecutionFilePath).Returns(targetUrl);
            mockRequest.Setup(c => c.HttpMethod).Returns(httpMethod);

            var mockResponse = new Mock<HttpResponseBase>();
            mockResponse.Setup(c => c.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(c => c);

            var mockContext =  new Mock<HttpContextBase>();
            mockContext.Setup(c=>c.Request).Returns(mockRequest.Object);
            mockContext.Setup(c => c.Response).Returns(mockResponse.Object);


            return mockContext.Object;
        }


        internal static void TestRouteMatch(RouteCollection routes, string url, string controller, string action, object routeProperties = null, string httpMethod = "Get")
        {
            //arrange
          
            //act
            var result = routes.GetRouteData(CreateHttpContext(url, httpMethod));
            //assert
            Assert.IsNotNull(result);
            Assert.IsTrue(TestIncomingRouteResults(result,controller,action,routeProperties));
            
        }



        internal static void TestGenerateUrl(RouteCollection routes, string controller, string action, string expectedUrl,  RouteValueDictionary routeValueDictionary = null, string httpMethod = "Get")
        {
            //arrange
            var httpContextBase = CreateHttpContext();
            var requestContext = new RequestContext(httpContextBase, new RouteData());
        
            //act
            string actualUrl = UrlHelper.GenerateUrl(null, action, controller, routeValueDictionary, routes,requestContext, true);

            //assert
           Assert.IsNotNull(actualUrl);
           Assert.AreEqual(expectedUrl,actualUrl);

        }

        internal static void TestRouteFail(RouteCollection routes, string url)
        {
            //arrange
               HttpContextBase httpContextBase = CreateHttpContext(url);
            //act
            var result = routes.GetRouteData(httpContextBase);
            //assert
            Assert.IsTrue(result==null||result.Route==null);
            
        }

        private static bool TestIncomingRouteResults(RouteData routeResult, string controller, string action,
                                              object propertySet = null)
        {
            Func<object, object, bool> valCompare = (v1, v2) => StringComparer.InvariantCultureIgnoreCase.Compare(v1, v2) ==0;

            bool result = valCompare(routeResult.Values["Controller"], controller) &&
                          valCompare(routeResult.Values["action"], action);

            if (propertySet != null)
            {
                var propInfo = propertySet.GetType().GetProperties();
                foreach (var pi in propInfo)
                {
                    if(!(routeResult.Values.ContainsKey(pi.Name) &&  valCompare(routeResult.Values[pi.Name] , pi.GetValue(propertySet, null) )))
                    {
                        result = false;
                        break;
                    }
                }
            }

            return result;
        }

    }
}